package day10;

import day10.handler.simpleChannelHandler.LoginResponseHandler;
import day10.handler.simpleChannelHandler.MessageResponseHandler;
import day10.handler.spliter.Spliter;
import day10.packet.LoginRequestPacket;
import day10.packet.MessageRequestPacket;
import day10.util.PacketCodeC;
import day10.util.coder.PacketDecoder;
import day10.util.coder.PacketEncoder;
import day10.util.session.SessionUtil;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;

import java.util.Date;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;

/**
 * @author chenshijie
 * @date 2023/12/23 16:24
 */

public class NettyClient {

    static int MAX_RETRY = 2;

    private static final String HOST = "127.0.0.1";

    private static final int port = 8001;

    public static void main(String[] args) {
        Bootstrap bootstrap = new Bootstrap();

        NioEventLoopGroup group = new NioEventLoopGroup();

        bootstrap
                .group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {

                        ch.pipeline().addLast(new Spliter());
                        ch.pipeline().addLast(new PacketDecoder());
                        ch.pipeline().addLast(new LoginResponseHandler());
                        ch.pipeline().addLast(new MessageResponseHandler());
                        ch.pipeline().addLast(new PacketEncoder());
                    }
                });
//                .handler(new ClientHandler());

        connect(bootstrap, HOST, port, MAX_RETRY);
    }

    private static void connect(Bootstrap bootstrap, String host, int port, int retry){
        GenericFutureListener<Future<? super Void>> futureListener = new GenericFutureListener<Future<? super Void>>() {
            @Override
            public void operationComplete(Future<? super Void> future) throws Exception {
                if (future.isSuccess()) {
                    System.out.println("连接成功！");
                    Channel channel = ((ChannelFuture) future).channel();
                    startConsoleThread(channel);

                } else if (retry == 0) {
                    System.err.println("重试次数过多，放弃连接！");
                    bootstrap.config().group().shutdownGracefully();


                } else {
                    int order = (MAX_RETRY - retry) + 1;
                    // 重连间隔
                    int delay = 1 << order;
                    System.err.println(new Date() + "：连接失败，第" + order + "次重连......");

                    bootstrap.config().group().schedule(() -> connect(bootstrap, host, port, retry - 1), delay, TimeUnit.SECONDS);

                }
            }
        };


        ChannelFuture channelFuture = bootstrap
                .connect(host, port)
                .addListener(futureListener);

    }

    private static void startConsoleThread(Channel channel) {
        Scanner sc = new Scanner(System.in);
        LoginRequestPacket loginRequestPacket = new LoginRequestPacket();

        new Thread(() -> {
            while (!Thread.interrupted()) {

                if (!SessionUtil.hasLogin(channel)) {
                    // 未登录
                    System.out.println("输入用户名登录: ");
                    String username = sc.nextLine();
                    loginRequestPacket.setUsername(username);
                    System.out.println("输入密码");
                    String password = sc.nextLine();
                    loginRequestPacket.setPassword(password);

                    channel.writeAndFlush(loginRequestPacket);
                    waitForLoginResponse();

                } else {
                    // 已登录
                    System.out.println("输入你想发送消息的用户");
                    String toUserId = sc.nextLine();
                    if (!isNumeric(toUserId)) {
                        System.err.println("输入账号有误");
                    } else {
                        System.out.println("输入消息");
                        String msg = sc.nextLine();
                        MessageRequestPacket messageRequestPacket = new MessageRequestPacket();
                        messageRequestPacket.setMessage(msg);
                        messageRequestPacket.setToUserId(Integer.parseInt(toUserId));

                        channel.writeAndFlush(messageRequestPacket);
                    }


                }
            }
        }).start();
    }

    private static void waitForLoginResponse() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static boolean isNumeric(String str){
        for (int i = str.length();--i>=0;){
            if (!Character.isDigit(str.charAt(i))){
                return false;
            }
        }
        return true;
    }

    private static void sendMsg(Channel channel, String msg) {
        MessageRequestPacket packet = new MessageRequestPacket();
        packet.setMessage(msg);
        ByteBuf byteBuf = PacketCodeC.INSTANCE.encode(channel.alloc(), packet);
        channel.writeAndFlush(byteBuf);
    }
}
